package pers.andy.websocket.tomcat;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import pers.andy.websocket.cache.SystemCache;

/**
 * tomcat websocket处理器
 * @author Andy.ye
 * @date 2018年4月8日 下午5:34:06
 */
@ServerEndpoint(value = "/websocket/tomcat/meeting", configurator = WebSocketHandshakeInterceptor.class)
public class MeetingWebSocketHandler {

	private static final Log LOG = LogFactory.getLog(MeetingWebSocketHandler.class);

	// 记录会议id和客户端关系
	private static ConcurrentHashMap<Integer, CopyOnWriteArraySet<Session>> meetingWsSeesionMap = new ConcurrentHashMap<>();
	// 与某个客户端的连接会话，需要通过它来给客户端发送数据
	private Session session;

	/**
	 * 连接建立成功调用的方法
	 * @param session 可选的参数。session为与某个客户端的连接会话，需要通过它来给客户端发送数据
	 */
	@OnOpen
	public void onOpen(Session session, EndpointConfig config) {
		LOG.info("tomcat websocket成功建立连接...");
		this.session = session;
		int meetingId = getMeetingId(session);
		if (meetingId <= 0) {
			singleMessage(session, "会议不存在!");
			try {
				session.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		// 如果该会议已存在，则直接加入
		if (meetingWsSeesionMap.containsKey(meetingId)) {
			CopyOnWriteArraySet<Session> webSocketSessions = meetingWsSeesionMap.get(meetingId);
			webSocketSessions.add(session);
		}
		// 如果不存在，则新建
		else {
			CopyOnWriteArraySet<Session> webSocketSessions = new CopyOnWriteArraySet<>();
			webSocketSessions.add(session);
			meetingWsSeesionMap.put(meetingId, webSocketSessions);
		}
	}

	/**
	 * 连接关闭调用的方法
	 */
	@OnClose
	public void onClose() {
		LOG.info("连接已关闭");
		int meetingId = getMeetingId(session);
		// role 1为主持人
		String role = String.valueOf(session.getUserProperties().get("role"));
		// 如果是主持人，则关闭所有该会议连接
		CopyOnWriteArraySet<Session> webSocketSessions = meetingWsSeesionMap.get(meetingId);
		if (StringUtils.equals("1", role)) {
			SystemCache.idRandStrMap.remove(meetingId);
			for (Session session : webSocketSessions) {
				try {
					session.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			webSocketSessions.remove(meetingId);
		} else {
			webSocketSessions.remove(session);
		}
	}

	/**
	 * 接收客户端的message,判断是否有接收人而选择进行广播还是指定发送
	 * @param _message 客户端发送过来的消息
	 */
	@OnMessage
	public void onMessage(String message) {
		if (!session.isOpen())
			return;
		LOG.info("接收到的消息：" + message);
		int meetingId = getMeetingId(session);
		broadcastMessage(meetingId, message);
	}

	/**
	 * 发生错误时调用
	 * @param error
	 */
	@OnError
	public void onError(Throwable error) {
		if (session.isOpen()) {
			try {
				session.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		LOG.info("连接出错", error);
	}

	/**
	 * 发送信息给指定用户
	 * @param clientId
	 * @param message
	 * @return
	 */
	public void singleMessage(Session session, String message) {
		if (!session.isOpen())
			return;
		try {
			session.getBasicRemote().sendText(message);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 广播信息
	 * @param message
	 * @return
	 */
	public void broadcastMessage(int meetingId, String message) {
		// 获取会议所有的wsSession
		CopyOnWriteArraySet<Session> webSocketSessions = meetingWsSeesionMap.get(meetingId);
		for (Session session : webSocketSessions) {
			try {
				if (session.isOpen()) {
					session.getBasicRemote().sendText(message);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private int getMeetingId(Session session) {
		String randStr = String.valueOf(session.getUserProperties().get("randStr"));
		int meetingId = SystemCache.getMeetingIdByRandStr(randStr);
		return meetingId;
	}
}
